---
title: Password Grant
excerpt: Authenticate users using username and password.
---

The Password Grant allows users to authenticate using their credentials i.e. their username and password.

## Demo

See [https://example-auth.next-drupal.org/](https://example-auth.next-drupal.org/).

## Flow

1. User provides their username and password on your Next.js site.
2. The username and password is sent via POST request to the API route `/api/auth/callback/credentials`.
3. We then send the credentials to the authorization server (Drupal) for authentication (server-side).
4. We get back an `access_token` for successful authentication.

## Dependencies

Add `next-auth` and `jwt-decode` to your Next.js site.

```sh
yarn add next-auth@beta jwt-decode
```

<Callout>

We are using NextAuth.js 4 beta in the examples but the stable 3.x release works as well (with a few tweaks).

</Callout>

## Installation

### Drupal

Create a new OAuth consumer:

1. Visit _/admin/config/services/consumer/add_
2. Fill in **Label** and **Secret**.
3. Click **Save**

### Next.js

1. Fill in the following in your `.env`:

```
OAUTH_CLIENT_ID= // The Consumer UUID created above.
OAUTH_CLIENT_SECRET= // The Client secret you added above.
NEXTAUTH_URL=http://localhost:3000 // The base url for your Next.js site
JWT_SIGNING_PRIVATE_KEY= // Generate one using `jose newkey -s 512 -t oct -a HS512`
```

2. Update your `_app.tsx` and wrap `Component` in a `SessionProvider.

```tsx title=pages/_app.tsx
import { AppProps } from "next/app"
import { SessionProvider } from "next-auth/react" // highlight-line

export default function App({
  Component,
  pageProps: { session, ...pageProps },
}: AppProps) {
  return (
    // highlight-start
    <SessionProvider session={session}>
      <Component {...pageProps} />
    </SessionProvider>
    // highlight-end
  )
}
```

3. Create the following API route `/pages/api/auth/[...nextauth].js`.

```tsx title=pages/api/auth/[...nextauth].js
import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
import jwt_decode from "jwt-decode"

export default NextAuth({
  providers: [
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        username: { label: "Username", type: "text", placeholder: "Username" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        const formData = new URLSearchParams()
        formData.append("grant_type", "password")
        formData.append("client_id", process.env.OAUTH_CLIENT_ID)
        formData.append("client_secret", process.env.OAUTH_CLIENT_SECRET)
        formData.append("username", credentials.username)
        formData.append("password", credentials.password)

        // Get access token from Drupal.
        const response = await fetch(
          `${process.env.NEXT_PUBLIC_DRUPAL_BASE_URL}/oauth/token`,
          {
            method: "POST",
            body: formData,
            headers: {
              "Content-Type": "application/x-www-form-urlencoded",
            },
          }
        )

        const data = await response.json()

        if (response.ok && data?.access_token) {
          return data
        }

        return null
      },
    }),
  ],
  jwt: {
    signingKey: process.env.JWT_SIGNING_PRIVATE_KEY,
    encryption: true,
  },
  callbacks: {
    async jwt({ token, user }) {
      // Forward the access token
      if (user) {
        token.accessToken = user.access_token
      }

      return token
    },
    async session({ session, token }) {
      if (token?.accessToken) {
        session.accessToken = token.accessToken

        // Decode token and pass info to session.
        // This data will be available client-side.
        const decoded = jwt_decode(token.accessToken)
        session.user.id = decoded.id
        session.user.email = decoded.email
        session.user.username = decoded.username
      }
      return session
    },
  },
})
```

4. If you visit `/api/auth/signin` you should now see the credentials authentication form.

<Img
  src="/images/next-auth-credentials.jpg"
  width="800"
  height="650"
  layout="responsive"
  alt="NextAuth.js Credentials Sign In"
  mb="10"
>
  <>NextAuth.js Credentials Sign In</>
</Img>

You can use this form to sign in.

<Callout>

The `/api/auth/signin` pages is a pre-built page that comes with NextAuth.js. If you would like to provide your own custom login page, [see the documentation](https://next-auth.js.org/configuration/pages).

</Callout>

## useSession

To handle authentication in your Next.js components, you can use the [`useSession`](https://next-auth.js.org/getting-started/client#usesession) hook.

```tsx
import { useSession } from "next-auth/react"

export default function Page() {
  const { data, status } = useSession()

  if (status === "authenticated") {
    return <p>Signed in as {data.user.email}</p>
  }

  return <a href="/api/auth/signin">Sign in</a>
}
```

## Additional information

### Drupal

When using the Password Grant, you can implement the `hook_simple_oauth_private_claims_alter` hook to pass additional information to the session.

```php
<?php

use Drupal\simple_oauth\Entities\AccessTokenEntity;
use Drupal\user\Entity\User;

/**
 * Implements hook_simple_oauth_private_claims_alter().
 */
function example_auth_simple_oauth_private_claims_alter(&$private_claims, AccessTokenEntity $access_token_entity) {
  $user_id = $access_token_entity->getUserIdentifier();
  /** @var \Drupal\user\UserInterface $user */
  $user = User::load($user_id);

  $private_claims = [
    'id' => $user->id(),
    'email' => $user->getEmail(),
    'username' => $user->getAccountName(),
    'field_name' => $user->get('field_name')->value, // highlight-line
  ];
}
```

### Next.js

Then update your `session` callback as follows:

```ts
callbacks: {
	async session({ session, token }) {
		if (token?.accessToken) {
			session.accessToken = token.accessToken

			// Decode token and pass info to session.
			// This data will be available client-side.
			const decoded = jwt_decode(token.accessToken)
			session.user.id = decoded.id
			session.user.email = decoded.email
			session.user.username = decoded.username
			session.user.field_name = decoded.field_name // highlight-line
		}
		return session
	},
},
```

### TypeScript

If you're using TypeScript, you can augment the `User` type with the additional information.

```ts title=types/next-auth.d.ts
import { DefaultSession, Session } from "next-auth"

declare module "next-auth" {
  interface Session {
    user?: DefaultSession["user"] & {
      field_name?: string
    }
  }
}
```
